using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RaycasterX;

namespace RaycasterXDemo
{
	public class Game1 : Microsoft.Xna.Framework.Game
	{
		#region Fields
		
		//standard stuff
		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;
		SpriteFont font;

		//our map
		Map map;

		//the camera
		Camera camera;

		//the renderer
		Renderer renderer;

		//a list of Sprites to draw
		List<Sprite> sprites = new List<Sprite>();

		//a comparison object used for depth sorting the sprites
		Comparison<Sprite> spriteDistanceSort = new Comparison<Sprite>(spriteSort);

		//we need a static reference to the camera for the comparison method
		static Camera tempCamera;

		#endregion

		#region Sort Method

		//this sorts all the sprites in back-to-front order
		static int spriteSort(Sprite a, Sprite b)
		{
			Vector2 ad = a.Position - tempCamera.Position;
			Vector2 bd = b.Position - tempCamera.Position;

			return bd.Length().CompareTo(ad.Length());
		}

		#endregion

		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";

			//no fixed time step and no vertical sync. by turning these
			//off, the game can run a little faster.
			IsFixedTimeStep = false;
			graphics.SynchronizeWithVerticalRetrace = false;

			//we use two resolutions based on whether we're compiling for Windows or Zune
#if !ZUNE
			//we can also use multisampling on Windows to make it look nicer
			graphics.PreferMultiSampling = true;
			graphics.PreferredBackBufferWidth = 1280;
			graphics.PreferredBackBufferHeight = 720;

			//create a new renderer at whaterever the preferred buffer size is
			renderer = new Renderer(
				graphics.PreferredBackBufferWidth,
				graphics.PreferredBackBufferHeight);

#else
			//create a new renderer at 240x320
			renderer = new Renderer(240, 320);
#endif
		}

		protected override void Initialize()
		{
			camera = new Camera();

			//create some values for the Position and Direction.
			//Direction should be a normalized vector.
			camera.Position = new Vector2(18.5f, 7.5f);
			camera.Direction = new Vector2(0f, -1f);

			//determine the desired FOV
			float fov = .66f;

			//get the perpendicular vector to the Direction multiplying by the FOV
			camera.Plane = new Vector2(camera.Direction.Y, -camera.Direction.X) * fov;

			//store the camera in the static reference for sprite sorting
			tempCamera = camera;

			base.Initialize();
		}

		protected override void LoadContent()
		{
			spriteBatch = new SpriteBatch(GraphicsDevice);

			//load the map
			map = Content.Load<Map>("Maps/Level1");
            
			//add some sprites to the level
			sprites.Add(new Sprite(new Vector2(20.5f, 12.5f), Content.Load<Texture2D>("Sprites/devil")));
			sprites.Add(new Sprite(new Vector2(5.5f, 12.5f), Content.Load<Texture2D>("Sprites/devil")));
			sprites.Add(new Sprite(new Vector2(13.5f, 5.5f), Content.Load<Texture2D>("Sprites/devil")));

			//load the font
			font = Content.Load<SpriteFont>("Fonts/Font");
		}

		protected override void Update(GameTime gameTime)
		{
			if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
				this.Exit();

            //Change by Patrick Pelletier - 20091120
#if !ZUNE
            camera.Update(
                (float)gameTime.ElapsedGameTime.TotalSeconds,
                Keyboard.GetState(PlayerIndex.One),
                map);
#else
            //update the camera
			camera.Update(
				(float)gameTime.ElapsedGameTime.TotalSeconds, 
                GamePad.GetState(PlayerIndex.One), 
				map);
#endif
            //End of change

            //sort the sprites
			sprites.Sort(spriteSort);

			//update the renderer
			renderer.Update(map, camera);

			base.Update(gameTime);
		}

		protected override void Draw(GameTime gameTime)
		{
			//draw the map. this draws the background and all the walls.
			renderer.Draw(spriteBatch, map);

			//draw all the sprites
			spriteBatch.Begin();
			foreach (Sprite s in sprites)
				renderer.DrawSprite(spriteBatch, camera, s);
			spriteBatch.End();

			base.Draw(gameTime);
		}
	}
}
